﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;

namespace Imager
{
    /// <summary>
    /// Description of UserControl1.
    /// </summary>
    public partial class ImageEditor : UserControl
    {
        private ComponentOfImage selectedComponent = null;
        private List<ComponentOfImage> drawingComponents = new List<ComponentOfImage>();
        private List<Marker> markers;

        public const int graffitiWidth = 586;
        public const int graffitiHeight = 293;

        private ComponentOfImage dragComponent = null;
        private Point dragStartPointInFigure;
        private Pen graffitiCroppingPart = new Pen(Color.Gray, 2);
        private Rectangle graffityPart;
        private Size CurrentSize;

        private enum DragTypes
        {
            move,
            resize
        }

        private DragTypes dragtype;

        public ImageEditor()
        {
            InitializeComponent();
            FontFamily[] ffArray = FontFamily.Families;
            foreach (FontFamily ff in ffArray)
            {
                this.comboBox1.Items.Add(ff.Name);
            }
            this.comboBox1.SelectedItem = "Arial";
            this.comboBox2.SelectedItem = "36";
        }

        public Image GetGraffityImage()
        {
            // nulled for not draw markers
            this.selectedComponent = null;
            if (markers != null)
                this.markers.Clear();
            // null for property working
            this.dragComponent = null;

            Image fullImg = new Bitmap(this.Width, this.Height);
            Graphics graphics = Graphics.FromImage(fullImg);
            var evens = new PaintEventArgs(graphics, this.ClientRectangle);
            this.ImageEditorPaint(null, evens);
            Image result = ((Bitmap) fullImg).Clone(this.graffityPart, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            graphics.Dispose();
            fullImg.Dispose();

            return result;
        }

        private const int MaxImageSize = 230*1024;
        private const double PosterizeStep = 0.05;

        public Stream GetPosterizedImage()
        {
            var originalImage = GetGraffityImage();
            double coeff = 1;
            long imagesize = long.MaxValue;
            Stream stream = null;
            while (imagesize > MaxImageSize)
            {
                if (stream != null)
                {
                    stream.Dispose();
                }
                stream = new MemoryStream();

                Bitmap resizedImage = new Bitmap(originalImage, (int) (originalImage.Width*coeff),
                                                 (int) (originalImage.Height*coeff));
                resizedImage.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
                resizedImage.Dispose();

                imagesize = stream.Length;

                coeff -= PosterizeStep;
            }
            stream.Seek(0, SeekOrigin.Begin);
            return stream;
        }

        private Rectangle GetGraffityPart()
        {
            return GetGraffityPart(this.Size);
        }

        private Rectangle GetGraffityPart(Size size)
        {
            graffityPart.Width = graffitiWidth;
            graffityPart.Height = graffitiHeight;
            graffityPart.X = (size.Width - graffitiWidth)/2;
            graffityPart.Y = (size.Height - graffitiHeight + 25)/2;
            return graffityPart;
        }

        private void ImageEditorPaint(object sender, PaintEventArgs e)
        {
            e.Graphics.FillRectangle(Brushes.White, GetGraffityPart());

            for (int i = drawingComponents.Count - 1; i >= 0; i--)
            {
                drawingComponents[i].Draw(e.Graphics);
            }

            if (selectedComponent != null)
            {
                selectedComponent.DrawBorder(e.Graphics);
            }

            if (sender != null)
            {
                e.Graphics.DrawRectangle(graffitiCroppingPart, GetGraffityPart());
            }

            if (markers != null)
            {
                foreach (var fig in markers)
                {
                    fig.Draw(e.Graphics);
                }
            }

            if (drawingComponents.Count == 0)
            {
                const string uploadYouImageHelp = "Дважды кликните или перетащите сюда изображение";
                SizeF box = e.Graphics.MeasureString(uploadYouImageHelp, this.Font);
                e.Graphics.DrawString(uploadYouImageHelp, this.Font, Brushes.Black, (this.Width - box.Width)/2,
                                      this.Height/2);
            }
        }

        private ComponentOfImage GetComponentInPosition(int x, int y)
        {
            if (markers != null)
            {
                foreach (var fig in markers)
                {
                    if (fig.border.Contains(x, y))
                        return fig;
                }
            }

            foreach (var fig in drawingComponents)
            {
                if (fig.IsInsidePoint(x, y))
                {
                    return fig;
                }
            }
            return null;
        }

        private void UpdateActiveText(object sender, EventArgs e)
        {
            if (selectedComponent != null && selectedComponent is TextComponent)
            {
                (selectedComponent as TextComponent).Font = GetUserFont();
            }
            this.Invalidate();
        }

        private Font GetUserFont()
        {
            try
            {
                FontStyle style = FontStyle.Regular;
                if (checkBox1.Checked)
                    style |= FontStyle.Bold;
                if (checkBox2.Checked)
                    style |= FontStyle.Italic;

                Font newFont = new Font(comboBox1.Text, int.Parse(this.comboBox2.Text), style);

                return newFont;
            }
            catch (Exception)
            {
            }
            // Safe return default font
            return this.Font;
        }

        private void SetUserFont(Font value)
        {
            this.comboBox1.Text = value.FontFamily.Name;
            this.comboBox2.Text = value.Size.ToString();
            this.checkBox1.Checked = value.Bold;
            this.checkBox2.Checked = value.Italic;
        }


        private void Button1Click(object sender, EventArgs e)
        {
            var textcomp = new TextComponent(this.Width/2, this.Height/2, this.Controls, GetUserFont());
            this.drawingComponents.Insert(0, textcomp);
        }

        private void Button2Click(object sender, EventArgs e)
        {
            if (selectedComponent is TextComponent)
            {
                var dialog = new ColorDialog();
                if (dialog.ShowDialog(this) == DialogResult.OK)
                {
                    (selectedComponent as TextComponent).TextColor = dialog.Color;
                }
                this.Invalidate();
            }
            else
            {
                MessageBox.Show("Не выбран текстовый компонет.", "Цвет можно менять только у текста",
                                MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void ButtonClearClick(object sender, EventArgs e)
        {
            selectedComponent = null;
            dragComponent = null;
            drawingComponents.Clear();
            this.Invalidate();
        }
    }
}